function GetEle(selector) {
    if (typeof selector == "string") { // ".list li"
        var list = document.querySelectorAll(selector); // 伪数组
    } else if (selector instanceof Element) {  //判断是单个原生DOM元素  li
        var list = [selector]; // [li]
    } else if (typeof selector == "object" && selector.length >= 0) {  // [li,li,li]
        var list = selector;
    }

    list = Array.from(list); //先转为真数组  => 赋值原值
    Object.setPrototypeOf(list, GetEle.prototype); // 在修改真数组的原型属性([[Prototype]])

    return list; // [ele,ele,ele,ele]  构造函数返回自定义实例化对象
}

// html()  设置和获取元素的(实例化对象=>伪数组)html结构
// html(123132)   有参数 => 就设置
// html()         没有参数 => 就获取 
GetEle.prototype.html = function (con) {
    // this => 调用此方法的实例化对象 => 获取元素的集合(伪数组)
    // arguments => 函数调用时实际参数的集合 
    if (arguments.length >= 1) { // 有至少一个参数

        //  this => 调用此方法的实例化对象 => 可以使用GetEle.prototype上所有的方法
        // for (var i = 0; i < this.length; i++) {
        //     var ele = this[i];
        //     ele.innerHTML = con;
        // }
        this.each(function (ele, i) {
            ele.innerHTML = con;
        })
        return this;
    } else { // 没有参数
        return this[0].innerHTML;
    }
}

// text()  设置和获取元素的(实例化对象=>伪数组)text结构
// text(123132)   有参数 => 就设置
// text()         没有参数 => 就获取 
GetEle.prototype.text = function (con) {
    // this => 调用此方法的实例化对象 => 获取元素的集合(伪数组)
    // arguments => 函数调用时实际参数的集合 
    if (arguments.length >= 1) { // 有至少一个参数
        // for (var i = 0; i < this.length; i++) {
        //     var ele = this[i];
        //     ele.innerText = con;
        // }

        this.each(function (ele, i) {
            ele.innerText = con;
        })
        return this;
    } else { // 没有参数
        return this[0].innerText;
    }
}


// val()  设置和获取元素的(实例化对象=>伪数组)val结构
// val(123132)   有参数 => 就设置
// val()         没有参数 => 就获取 
GetEle.prototype.val = function (con) {
    // this => 调用此方法的实例化对象 => 获取元素的集合(伪数组)
    // arguments => 函数调用时实际参数的集合 
    if (arguments.length >= 1) { // 有至少一个参数
        // for (var i = 0; i < this.length; i++) {
        //     var ele = this[i];
        //     ele.value = con;
        // }

        this.each(function (ele, i) {
            ele.value = con;
        })
        return this;
    } else { // 没有参数
        return this[0].value;
    }
}


// hide  show

// hide()  隐藏集合(实例化对象)中的每一个元素
GetEle.prototype.hide = function () {
    // this => 调用此方法的实例化对象 => 获取元素的集合(伪数组)
    // for (var i = 0; i < this.length; i++) {
    //     var ele = this[i];
    //     ele.style.display = "none";
    // }
    this.each(function (ele, i) {
        ele.style.display = "none";
    })
    return this;
}

// show()  显示集合(实例化对象)中的每一个元素
GetEle.prototype.show = function () {
    // this => 调用此方法的实例化对象 => 获取元素的集合(伪数组)
    // for (var i = 0; i < this.length; i++) {
    //     var ele = this[i];
    //     ele.style.display = "block";
    // }

    this.each(function (ele, i) {
        ele.style.display = "block";
    })
    return this;
}

// on(type,callback)    给集合中的每个元素绑定事件
// type 绑定事件的类型
// callback  事件触发时执行的回调函数
GetEle.prototype.on = function (type, callback) {
    // for (var i = 0; i < this.length; i++) {
    //     var ele = this[i];
    //     ele.addEventListener(type, callback);
    // }

    this.each(function (ele, i) {
        ele.addEventListener(type, callback);
    })
    return this;
}

// off(type,callback)    对应回调函数,清除集合中的每个元素绑定的事件
// type 绑定事件的类型
// callback  事件触发时执行的回调函数
GetEle.prototype.off = function (type, callback) {
    // for (var i = 0; i < this.length; i++) {
    //     var ele = this[i];
    //     ele.removeEventListener(type, callback);
    // }

    this.each(function (ele, i) {
        ele.removeEventListener(type, callback);
    })
    return this;
}

// jquery中所有类型的事件 都是基于on()方法二次封装得到的
GetEle.prototype.click = function (callback) {
    // this => 调用此方法的实例化对象 => 获取元素的集合(伪数组)
    this.on("click", callback);
    return this;
}
GetEle.prototype.dblclick = function (callback) {
    // this => 调用此方法的实例化对象 => 获取元素的集合(伪数组)
    this.on("dblclick", callback);
    return this;
}
GetEle.prototype.mousedown = function (callback) {
    // this => 调用此方法的实例化对象 => 获取元素的集合(伪数组)
    this.on("mousedown", callback);
    return this;
}
GetEle.prototype.mousemove = function (callback) {
    // this => 调用此方法的实例化对象 => 获取元素的集合(伪数组)
    this.on("mousemove", callback);
    return this;
}
GetEle.prototype.mouseup = function (callback) {
    // this => 调用此方法的实例化对象 => 获取元素的集合(伪数组)
    this.on("mouseup", callback);
    return this;
}

// width()   获取和设置集合中元素(实例化对象)的宽度
// width("200px")  
// width()  
GetEle.prototype.width = function (val) {
    // this => 调用此方法的实例化对象 => 获取元素的集合(伪数组)
    if (arguments.length >= 1) { //有参数
        this.each(function (ele, i) {
            // 判断是否有单位  
            // 有单位 直接赋值   => 1 px pt em rem % vw vh vmin vmax 
            // 没有单位 默认px
            var reg = /^\d+(px|pt|em|rem|%|vw|vh|vmin|vmax)$/;
            if (reg.test(val)) {
                ele.style.width = val;
            } else {
                ele.style.width = val + "px";
            }

        })
        return this;
    } else { // 没有参数
        return parseInt(this.getStyle("width"));
    }
}


// height()   获取和设置集合中元素(实例化对象)的宽度
// height("200px")  
// height()  
GetEle.prototype.height = function (val) {
    // this => 调用此方法的实例化对象 => 获取元素的集合(伪数组)
    if (arguments.length >= 1) { //有参数
        this.each(function (ele, i) {
            // 判断是否有单位  
            // 有单位 直接赋值   => 1 px pt em rem % vw vh vmin vmax 
            // 没有单位 默认px
            var reg = /^\d+(px|pt|em|rem|%|vw|vh|vmin|vmax)$/;
            if (reg.test(val)) {
                ele.style.height = val;
            } else {
                ele.style.height = val + "px";
            }

        })
        return this;
    } else { // 没有参数
        return parseInt(this.getStyle("height"));
    }
}

// css()    获取和设置集合中元素(实例化对象)的css样式
// css("width","200px")    有两个参数就设置
// css("width");           有一个参数就获取

GetEle.prototype.css = function (key, val) {
    // this => 调用此方法的实例化对象 => 获取元素的集合(伪数组)
    if (arguments.length >= 2) { // 有两个参数就设置
        this.each(function (ele, index) {
            ele.style[key] = val;
        })
        return this;
    } else if (arguments.length == 1) { // 有一个参数

        if (typeof key == "string") {
            // css("width");  有一个参数,且是字符串 => 取值 => 默认返回第一个
            var ele = this[0];
            try {
                return window.getComputedStyle(ele)[key];
            } catch (err) {
                return ele.currentStyle[key];
            }
        } else if (Object.prototype.toString.call(key) === "[object Object]") {
            // css({background:"red",width:"200px"})  有一个参数,且是对象  => 获取键名和键值 设置
            for (var cssKey in key) {
                var cssVal = key[cssKey];
                this.css(cssKey, cssVal);
            }
            return this;
        }


    } else {
        var err = new Error("Please pass in at least one parameter!");
        throw err;
    }
}

GetEle.prototype.getStyle = function (key) {
    // this => 调用此方法的实例化对象 => 获取元素的集合(伪数组)
    var ele = this[0];
    try {
        return window.getComputedStyle(ele)[key];
    } catch (err) {
        return ele.currentStyle[key];
    }
}

// addClass()      给集合中元素(实例化对象)添加一个或多个class名(多class名之间用空格分隔  "one two three")
// removeClass()   删除集合中元素(实例化对象)一个或多个class名(多class名之间用空格分隔  "one two three")
// toggleClass()   对集合中元素(实例化对象)的class名进行切换  (没有就新增 有就删除)
// hasClass()      判断对集合中元素是否存在某个class名 (只要有一个存在则返回true)

GetEle.prototype.addClass = function (classStr) {
    // 多class名之间用空格分隔  "one two three"
    var list = classStr.split(" "); // ["one","two","three"]
    this.each(function (ele, i) {
        ele.classList.add(...list);
    })
    return this;
}

GetEle.prototype.removeClass = function (classStr) {
    // 多class名之间用空格分隔  "one two three"
    var list = classStr.split(" "); // ["one","two","three"]
    this.each(function (ele, i) {
        ele.classList.remove(...list);
    })
    return this;
}

GetEle.prototype.toggleClass = function (classStr) {
    this.each(function (ele, i) {
        ele.classList.toggle(classStr);
    })
    return this;
}

// 判断对集合中元素是否存在某个class名 (只要有一个存在则返回true)
GetEle.prototype.hasClass = function (classStr) {
    var flag = false;//假设集合中不存在某个class名
    this.each(function (ele, i) {
        if (ele.classList.contains(classStr)) {
            flag = true;
        }
    })
    return flag;
}

// attr(key,val)   获取和设置集合中元素(实例化对象)的属性节点
// attr("class","one")  有两个参数就设置
// attr("class")        有一个参数就获取
GetEle.prototype.attr = function (key, val) {
    // this => 调用此方法的实例化对象 => 获取元素的集合(伪数组)
    if (arguments.length >= 2) {
        this.each(function (ele) {
            ele.setAttribute(key, val);
        })
        return this;
    } else if (arguments.length == 1) {
        return this[0].getAttribute(key);
    }
}

// prop(key,val)   获取和设置集合中元素(实例化对象)的属性
// prop("className","one")  有两个参数就设置   ele.className ele.clientWidth ele.offsetLeft
// prop("className")        有一个参数就获取
GetEle.prototype.prop = function (key, val) {
    if (arguments.length >= 2) {
        this.each(function (ele) {
            ele[key] = val;
        })
        return this;
    } else if (arguments.length == 1) {
        return this[0][key];
    }
}

// eq(index)  传入一个下标 返回对应下标的元素形成的实例化对象
// $('.list li').eq(2).css({background:"red"})
GetEle.prototype.eq = function (index) {
    // this => 调用此方法的实例化对象 => 获取元素的集合(伪数组)
    // return this[index];  //原生DOM元素 => 只能使用原生DOM的属性和方法
    return $(this[index]); // $(原生DOM元素)  => 对应的实例化对象
}

// siblings()   每一个被选中元素(实例化对象中)的所有的同级元素的集合
// $('.list li').eq(2).siblings().css({background:"green"})
// $('.first,.last').siblings().css({ background: "green" })

// 单元素  直接找同级
// 多元素  找每一个元素的同级  => 并级
GetEle.prototype.siblings = function () {
    // this => 调用此方法的实例化对象 => 获取元素的集合(伪数组)
    // this => 调用此方法的实例化对象 => 被选中元素的集合   [li.first,li.last]
    var all = [];
    this.each(function (item) { //找到每一个被选中的元素
        var parentEle = item.parentElement;  //找父元素
        var children = parentEle.children; // 父元素所有的子元素
        var list = Array.from(children).filter((ele => ele != item));
        all = all.concat(list);  // concat() 返回拼接后的新数组
    })
    all = [...new Set(all)]; //去除重复项

    return $(all); // 转化为实例化对象
}

// index()  返回匹配的元素相对于同级元素的下标(如果有多个默认返回第一个)
// $(".mid").index();
GetEle.prototype.index = function () {
    // this => 调用此方法的实例化对象 => 获取元素的集合(伪数组)
    var ele = this[0]; //默认取集合中的第一个元素
    var parentEle = ele.parentElement;  //找父元素
    var children = parentEle.children; // 父元素所有的子元素
    var index = Array.from(children).findIndex(item => item === ele); // 匹配的元素相对于同级元素的下标
    return index;
}





GetEle.prototype.each = function (callback) { // 回调函数 => 每次循环时执行
    // this => 调用此方法的实例化对象 => 获取元素的集合(伪数组)
    for (var i = 0; i < this.length; i++) { // 传入一个回调函数 每次循环时执行
        var item = this[i]; // 循环的当前元素
        var index = i;  // 循环的当前下标
        callback(item, index); //两个实参 
    }
    return this;
}

function $(selector) { // 接收css选择器 => 返回对应的实例化对象
    return new GetEle(selector);
}